(function() {

    var coreModule = {

        modules : { },

        namespace : function(path) {
            var items = path.split('.'), currentNamespace = window, i;

            for (i = 0; i < items.length; ++i) {
                var key = items[i];
                currentNamespace[key] = currentNamespace[key] || { };
                currentNamespace = currentNamespace[key];
            }

            return currentNamespace;
        },

        parseCompositeModuleName : function(compositeName) {
            var index = compositeName.indexOf('-');

            if (index == -1) {
                if (compositeName.indexOf('*') != -1) {
                    return { namespace : compositeName.replace('.*', '') };
                } else {
                    index = compositeName.length - 1;
                }
            }

            while (--index > -1) {
                if (compositeName.charAt(index) == '.') break;
            }

            return { namespace : compositeName.substr(0, index), name : compositeName.substr(index + 1) };
        },

        using : function(o) {
            var self = this;

            return (function(key) {
                if (typeof o[key] != 'string') {
                    if (!o[key]) {
                        logger.error('Module with alias %s not found.', key);
                    }

                    return o[key];
                }

                var result = self.parseCompositeModuleName(o[key]);

                if (!result.name) {
                    self.loadModule(result.namespace);
                    o[key] = self.namespace(result.namespace);
                } else {
                    o[key] = self.loadModule(result.namespace, result.name);
                }

                return o[key];
            });
        },

        compileModule : function(namespace, name) {
            var testModule = this.modules[namespace][name];

            if (typeof testModule.link != 'string') return testModule;

            logger.debug('Source code for module %s.%s compiled.', namespace, name);
            eval(testModule.link);
            
            return this.modules[namespace][name];
        },

        isModuleRegistered : function(namespace, name) {
            var currentModules = this.modules[namespace];
            return (currentModules && currentModules[name]);
        },
        
        loadModule : function(namespace, name) {
            var currentModules = this.modules[namespace];

            if (!name) {
                for (var moduleName in currentModules) this.loadModule(namespace, moduleName);
                return;
            }

            if (!currentModules || !currentModules[name]) {
                logger.error('Module %s.%s not found.', namespace, name);
            }

            var module = currentModules[name];

            if (!module.loaded) {
                module = this.compileModule(namespace, name);
                (this.namespace(namespace))[name] = module.link;
                module.loaded = true;
                logger.debug('Module %s.%s loaded.', namespace, name);
            }

            return module.link;
        },

        registerModule : function(namespace, name, link) {
            var m = this.modules;

            if (m[namespace] && m[namespace][name] && (typeof m[namespace][name].link == typeof link)) {
                logger.error('Module %s.%s already registered.', namespace, name);
            }

            m[namespace] = m[namespace] || { };
            m[namespace][name] = { loaded : false, link : link };

            if (typeof link == 'string') {
                logger.debug('Source code for module %s.%s registered.', namespace, name);
            } else {
                logger.debug('Module %s.%s registered.', namespace, name);
            }
        },

        createObject : function(clazz, o) {
            var result = new clazz();
            if (result.initialize) result.initialize(o);
            return result;
        },

        bindGlobalObject : function(name, obj) {
            juliet[name] = obj;
            logger.debug('Global object %s binded.', name);
        },
        
        bindGlobalFunction : function(name, func) {
            var self = this;

            juliet[name] = function() {
                return func.apply(self, arguments);
            };

            logger.debug('Global function %s binded.', name);
        }

    };

    coreModule.registerModule('juliet.core', 'core-0.1', coreModule);
    coreModule.loadModule('juliet.core', 'core-0.1');

    coreModule.bindGlobalFunction('registerModule', coreModule.registerModule);
    coreModule.bindGlobalFunction('using', coreModule.using);
    coreModule.bindGlobalFunction('createObject', coreModule.createObject);
    coreModule.bindGlobalFunction('isModuleRegistered', coreModule.isModuleRegistered);

    if (window.jQuery) {
        coreModule.bindGlobalObject('jQuery', jQuery);
    }

})();
